/**
 *
 * Created : Feb 19, 2012
 *
 * @author pquiring
 */

import java.util.*;
import java.io.*;

import jfparted.*;
import javaforce.*;
import javaforce.linux.*;

public class Install extends IPanel implements ShellProcessListener {

  /**
   * Creates new form Install
   */

  public Install() {
    initComponents();
    Data.getDevices();
    Data.getPartitions();
    Installer.disableButtons();
    //create a Thread
    Worker worker = new Worker();
    worker.start();
  }

  private class Optional extends Exception {
    public Optional(String msg) {
      super(msg);
    }
  };

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    jScrollPane1 = new javax.swing.JScrollPane();
    log = new javax.swing.JTextArea();
    progress = new javax.swing.JProgressBar();

    log.setColumns(20);
    log.setEditable(false);
    log.setRows(5);
    jScrollPane1.setViewportView(log);

    progress.setToolTipText("");

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    this.setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
      .addComponent(progress, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
    );
  }// </editor-fold>//GEN-END:initComponents
  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JScrollPane jScrollPane1;
  private javax.swing.JTextArea log;
  private javax.swing.JProgressBar progress;
  // End of variables declaration//GEN-END:variables

  private int totalFilesCopied = 0, filesToCopy = 0;
  private boolean calcFilesToCopy = false;
  private boolean fedoraMount = false;

  public class Worker extends Thread {
    public void run() {
      ShellProcess sp;
      ArrayList<String> cmd;
      String output;

      //disable all swaps (can prevent deleting old parts)
      sp = new ShellProcess();
      cmd = new ArrayList<String>();
      cmd.add("sudo");
      cmd.add("swapoff");
      cmd.add("-a");
      output = sp.run(cmd, false);
      if ((output == null) || (sp.getErrorLevel() != 0)) {
        addLog("Error:Failed to exec swapoff");
        JFLog.log("ErrorLevel=" + sp.getErrorLevel());
        abort();
        return;
      }

      //umount any parts that startsWith(Data.root.device.dev)
      sp = new ShellProcess();
      cmd = new ArrayList<String>();
      cmd.add("mount");
      output = sp.run(cmd, false);
      if ((output == null) || (sp.getErrorLevel() != 0)) {
        addLog("Error:Failed to exec mount");
        JFLog.log("ErrorLevel=" + sp.getErrorLevel());
        abort();
        return;
      }
      String lns[] = output.split("\n");
      for(int a=0;a<lns.length;a++) {
        if (lns[a].startsWith(Data.root.device.dev)) {
          int idx = lns[a].indexOf(" ");
          if (!Data.umount(lns[a].substring(0, idx))) {
            addLog("Error:Failed to exec umount");
            abort();
            return;
          }
        }
      }

      if (Linux.distro == Linux.DistroTypes.Fedora) {
        //need to mount CD under /mnt/src
        Data.mount("/dev/mapper/live-osimg-min", "/mnt/src");
        fedoraMount = true;
      }

      //do guided part stuff
      if (Data.guidedTarget != null) {
        //perform ops1 (removes)
        addLog("Partitioning device...");
        sp = new ShellProcess();
        cmd = new ArrayList<String>();
        cmd.add("sudo");
        cmd.add("parted");
        for(int a=0;a<Data.ops1.size();a++) sp.addResponse("(parted) ", Data.ops1.get(a), false);
        output = sp.run(cmd, false);
        if ((output == null) || (output.indexOf("Error:") != -1) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to remove old partitions.\nAre they mounted?");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }

        //perform ops2 (mkpart's)
        sp = new ShellProcess();
        cmd = new ArrayList<String>();
        cmd.add("sudo");
        cmd.add("parted");
        for(int a=0;a<Data.ops2.size();a++) sp.addResponse("(parted) ", Data.ops2.get(a), false);
        output = sp.run(cmd, false);
        if ((output == null) || (output.indexOf("Error:") != -1) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to create new partitions.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
        //format / and swap
        addLog("Formatting new partitions...");
        Data.root.label = "OS";
        if (!Data.format(Data.root)) {
          addLog("Error:Failed to format root partition");
          abort();
          return;
        }
        addLog("...swap...");
        Data.swap.label = "SWAP";
        if (!Data.format(Data.swap)) {
          addLog("Error:Failed to format swap partition");
          abort();
          return;
        }
      }

      //refresh partition lists
      Data.getDevices();
      Data.getPartitions();

      // confirm Data.root == ext4 & Data.swap == swap
      String rootdev = Data.root.device.dev + Data.root.number;
      String swapdev = "";
      if (Data.swap != null) swapdev = Data.swap.device.dev + Data.swap.number;
      boolean rootOk = false;
      boolean swapOk = false;
      if (Data.swap == null) swapOk = true;
      for(int d=0;d<Data.devices.size();d++) {
        Data.Device device = Data.devices.get(d);
        for (int p=0;p<device.parts.size();p++) {
          Data.Partition part = device.parts.get(p);
          if (part.number == -1) continue;
          String partdev = part.device.dev + part.number;
          if (partdev.equals(rootdev)) {
            if (part.filesys.startsWith("ext")) {
              rootOk = true;
            }
          }
          if ((Data.swap != null) && (partdev.equals(swapdev))) {
            if (part.filesys.equals("swap")) {
              swapOk = true;
            }
          }
        }
      }
      if (!rootOk) {
        addLog("Error:Unable to find root partition.");
        abort();
        return;
      }
      if (!swapOk) {
        addLog("Error:Unable to find swap partition.");
        abort();
        return;
      }
      // mount Data.root
      if (!Data.mount(Data.root, "/mnt/install")) {
        addLog("Error:Failed to mount root partition.");
        abort();
        return;
      }
      //load filesToCopy from /etc/.live
      try {
        Properties props = new Properties();
        FileInputStream etclive = new FileInputStream("/etc/.live");
        props.load(etclive);
        etclive.close();
        filesToCopy = JF.atoi(props.getProperty("filesToCopy"));
      } catch (Exception e) {
        JFLog.log(e);
      }
      if (filesToCopy <= 0) {
        addLog("Calculating files to copy...");
        sp = new ShellProcess();
        cmd = new ArrayList<String>();
        cmd.add("sudo");
        cmd.add("rsync");
        cmd.add("-aHAXvn");  //archive + H A X + verbose + dry run
        if (Linux.distro == Linux.DistroTypes.Ubuntu)
          cmd.add("/rofs/.");
        else
          cmd.add("/mnt/src/.");
        cmd.add("/mnt/install");
        sp.addListener(Install.this);
        sp.log = false;  //too much
        sp.keepOutput(false);
        calcFilesToCopy = true;
        output = sp.run(cmd, false);
        calcFilesToCopy = false;
        sp.log = true;
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to calculate files to copy.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
//        addLog("filesToCopy=" + filesToCopy);
        System.out.println("filesToCopy=" + filesToCopy);
      }

      sp = new ShellProcess();
      cmd = new ArrayList<String>();
      addLog("Copying files...");
      cmd.add("sudo");
      cmd.add("rsync");
      cmd.add("-aHAXv");  //archive + H A X + verbose
      if (Linux.distro == Linux.DistroTypes.Ubuntu)
        cmd.add("/rofs/.");
      else
        cmd.add("/mnt/src/.");
      cmd.add("/mnt/install");
      sp.addListener(Install.this);
      sp.log = false;  //too much
      sp.keepOutput(false);
      output = sp.run(cmd, false);
      sp.log = true;
      sp.addListener(null);
      if ((output == null) || (sp.getErrorLevel() != 0)) {
        addLog("Error:Failed to copy files.");
        JFLog.log("ErrorLevel=" + sp.getErrorLevel());
        abort();
        return;
      }
      ShellProcess.log = true;
      //modify new installation
      // : create skipped folders
/*      Data.mkdir("/mnt/install/dev");
      Data.mkdir("/mnt/install/proc");
      Data.mkdir("/mnt/install/tmp");
      Data.chmod("/mnt/install/tmp", "1777");
      Data.mkdir("/mnt/install/sys");
      Data.mkdir("/mnt/install/run");
      Data.mkdir("/mnt/install/run/lock");
      Data.chmod("/mnt/install/run/lock", "1777");*/
      // : fstab
      addLog("Generating fstab...");
      try {
        FileOutputStream fos = new FileOutputStream("/tmp/fstab");
        fos.write("#fstab generated by jfinstall\n".getBytes());
        for(int a=0;a<Data.fstab.size();a++) {
          fos.write((Data.fstab.get(a) + "\n").getBytes());
        }
        fos.close();
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("cp");
        cmd.add("/tmp/fstab");
        cmd.add("/mnt/install/etc/fstab");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to setup fstab.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("fstab creation failed");
        abort();
        return;
      }
      addLog("Creating new user...");
      // : add new user
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("chroot");
        cmd.add("/mnt/install");
        cmd.add("useradd");
        cmd.add("-s");
        cmd.add("/bin/bash");
        cmd.add("-m");
        cmd.add("-G");
        switch (Linux.distro) {
          case Ubuntu: cmd.add("sudo"); break;  //allows sudo (Ubuntu 12.04)
//        cmd.add("admin");  //allows sudo (Ubuntu 11.10)
          case Fedora: cmd.add("wheel"); break;  //allows sudo (Fedora)
        }
        cmd.add("-c");
        cmd.add("\"" + Data.fullName + "\"");
        cmd.add(Data.loginName);
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to create new user.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to create new user.");
        abort();
        return;
      }
      // : set new user passwd
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("chroot");
        cmd.add("/mnt/install");
        cmd.add("passwd");
        cmd.add(Data.loginName);
        //ubuntu???
        sp.addResponse("Enter new UNIX password:", Data.passwd + "\n", true);
        sp.addResponse("Retype new UNIX password:", Data.passwd + "\n", true);
        //fedora (f19)
        sp.addResponse("New password:", Data.passwd + "\n", true);
        sp.addResponse("Retype new password:", Data.passwd + "\n", true);
        output = sp.run(cmd, true);  //NOTE : prompts are sent to stderr
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to create new user passwd.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to create new user passwd.");
        abort();
        return;
      }
      // : delete /etc/.live
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("rm");
        cmd.add("/mnt/install/etc/.live");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to delete /etc/.live");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to delete /etc/.live");
        abort();
        return;
      }
      // : assign hostname & domain
      addLog("Assign computer name & domain...");
      try {
        File tmpFile1 = File.createTempFile("hostname", ".tmp");
        FileOutputStream fos1 = new FileOutputStream(tmpFile1);
        fos1.write(Data.localhost.getBytes());
        fos1.close();

        File tmpFile2 = File.createTempFile("hosts", ".tmp");
        FileOutputStream fos2 = new FileOutputStream(tmpFile2);
        FileInputStream fis2 = new FileInputStream("/mnt/install/etc/hosts");
        BufferedReader br = new BufferedReader(new InputStreamReader(fis2));
        String ln;
        while ((ln = br.readLine()) != null) {
          if (ln.startsWith("127.0.0.1")) {
            ln = "127.0.0.1\tlocalhost " + Data.localhost;
          }
          fos2.write((ln + "\n").getBytes());
        }
        fos2.close();
        fis2.close();

        if (!Linux.runScript(new String[] {
          "cp " + tmpFile1.getAbsolutePath() + " /mnt/install/etc/hostname",
          "cp " + tmpFile2.getAbsolutePath() + " /mnt/install/etc/hosts",
          })) {

          tmpFile1.delete();
          throw new Exception("file io error");
        }
        tmpFile1.delete();
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to set hostname.");
        abort();
        return;
      }
      try {
        File tmpFile = File.createTempFile("network", ".xml");
        FileOutputStream fos = new FileOutputStream(tmpFile);
        fos.write(("<network>\n  <hostname>" + Data.localhost + "</hostname>\n  <domain>" + Data.localdomain + "</domain>\n</network>\n").getBytes());
        fos.close();
        if (!Linux.copyFile(tmpFile.getAbsolutePath(), "/mnt/install/etc/jconfig.d/network.xml")) {
          throw new Exception("file io error");
        }
        tmpFile.delete();
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to save network config.");
        abort();
        return;
      }

      //set timezone
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("chroot");
        cmd.add("/mnt/install");
        cmd.add("rm");
        cmd.add("/etc/localtime");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to delete current timezone.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to delete current timezone.");
        abort();
        return;
      }
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("chroot");
        cmd.add("/mnt/install");
        cmd.add("ln");
        cmd.add("-s");
        cmd.add("/usr/share/zoneinfo/" + Data.timezone);
        cmd.add("/etc/localtime");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to assign timezone.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to assign timezone.");
        abort();
        return;
      }
      try {
        File file = new File("/tmp/timezone");
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(Data.timezone.getBytes());
        fos.close();
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("cp");
        cmd.add("/tmp/timezone");
        cmd.add("/mnt/install/etc/timezone");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to assign timezone.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
        file.delete();
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to assign timezone.");
        abort();
        return;
      }

      // : set root part bootable (parted : set $Data.root.number boot on)
      addLog("Setting boot partition...");
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("parted");
        sp.addResponse("(parted) ", "select " + Data.root.device.dev + "\n", false);
        sp.addResponse("(parted) ", "set " + Data.root.number + " boot on\n", false);
        sp.addResponse("(parted) ", "quit\n", false);
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to set bootable partition.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to set bootable partition.");
        abort();
        return;
      }
      // : install grub
      addLog("Installing boot loader...");
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        if (new File("/usr/sbin/grub2-install").exists())
          cmd.add("grub2-install");
        else if (new File("/usr/sbin/grub-install").exists())
          cmd.add("grub-install");
        else throw new Exception("grub tools not found");
        cmd.add(Data.root.device.dev);
        cmd.add("--boot-directory=/mnt/install/boot");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to exec " + cmd.get(1));
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("grub install failed");
        abort();
        return;
      }
      //get `uname -r`
      sp = new ShellProcess();
      //create initramfs
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("jfinstall-chroot.sh");
        cmd.add("/mnt/install");
        if (Linux.distro == Linux.DistroTypes.Fedora) {
          //fedora way
          cmd.add("dracut");
        } else {
          //ubuntu way
          String uname = sp.run(new String[] {"uname", "-r"}, false).replaceAll("\n", "");
          cmd.add("mkinitramfs");
          cmd.add("-o");
          cmd.add("/boot/initrd.img-" + uname);
        }
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to exec " + cmd.get(3));
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("create initramfs failed");
        abort();
        return;
      }
      //grub mkconfig
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("jfinstall-chroot.sh");
        cmd.add("/mnt/install");
        if (new File("/usr/sbin/grub2-mkconfig").exists()) {
          cmd.add("grub2-mkconfig");
          cmd.add("--output=/boot/grub2/grub.cfg");
        } else if (new File("/usr/sbin/grub-mkconfig").exists()) {
          cmd.add("grub-mkconfig");
          cmd.add("--output=/boot/grub/grub.cfg");
        } else {
          throw new Exception("grub tools not found");
        }
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to exec " + cmd.get(3) );
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("grub mkconfig failed");
        abort();
        return;
      }
      //grub mkdevicemap (optional)
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("jfinstall-chroot.sh");
        cmd.add("/mnt/install");
        if (new File("/usr/sbin/grub2-mkdevicemap").exists())
          cmd.add("grub2-mkdevicemap");
        else if (new File("/usr/sbin/grub-mkdevicemap").exists())
          cmd.add("grub-mkdevicemap");
        else throw new Optional("device.map will not be created");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to exec " + cmd.get(3));
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Optional e) {
        JFLog.log(e.toString());
      } catch (Exception e) {
        JFLog.log(e);
        addLog("grub mkdevicemap failed");
        abort();
        return;
      }

      addLog("Removing unneeded packages...");
      // : remove unneeded packages
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("chroot");
        cmd.add("/mnt/install");
        switch (Linux.distro) {
          case Ubuntu:
            cmd.add("apt-get");
            cmd.add("--yes");
            break;
          case Fedora:
            cmd.add("yum");
            cmd.add("-y");
            break;
        }
        cmd.add("remove");
        switch (Linux.distro) {
          case Ubuntu:
            cmd.add("casper");
            cmd.add("lupin-casper");
            break;
        }
        cmd.add("jfinstall");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Error:Failed to remove unneeded packages.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
          abort();
          return;
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Error:Failed to remove unneeded packages.");
        abort();
        return;
      }
/*
      addLog("Installing 'extra' packages...");
      //install restricted packages (ffmpeg, chrome)
      try {
        sp = new ShellProcess();
        cmd.clear();
        cmd.add("sudo");
        cmd.add("chroot");
        cmd.add("/mnt/install");
        switch (Linux.distro) {
          case Ubuntu:
            cmd.add("apt-get");
            cmd.add("--yes");
            break;
          case Fedora:
            cmd.add("yum");
            cmd.add("-y");
            break;
        }
        cmd.add("install");
        switch (Linux.distro) {
          case Ubuntu:
            cmd.add("libav-tools");
            break;
          case Fedora:
            cmd.add("ffmpeg");
            break;
        }
        cmd.add("google-chrome-stable");
        output = sp.run(cmd, false);
        if ((output == null) || (sp.getErrorLevel() != 0)) {
          addLog("Warning:Failed to install extra packages.");
          JFLog.log("ErrorLevel=" + sp.getErrorLevel());
        }
      } catch (Exception e) {
        JFLog.log(e);
        addLog("Warning:Failed to install extra packages.");
      }
*/
      //delete some fedora live files
/*
      //even Fedora installers don't touch this stuff
      if (Linux.distro == Linux.DistroTypes.Fedora) {
        try {
          new File("/etc/rc.d/init.d/livesys").delete();
          new File("/etc/rc.d/init.d/livesys-late").delete();
          new File("/sbin/halt.local").delete();
        } catch (Exception e) {
          JFLog.log(e);
        }
      }
*/
      //unmount root part
      Data.umount(Data.root.device.dev + Data.root.number);
      if (Linux.distro == Linux.DistroTypes.Fedora) {
        if (fedoraMount) {
          Data.umount("/mnt/src");
          fedoraMount = false;
        }
      }
      //done!
      addLog("Installation complete");
      progress.setValue(100);
      Installer.enableFinish();
    }
  }

  private void addLog(String msg) {
    log.setText(log.getText() + msg + "\n");
    JFLog.log(msg);
  }

  private void abort() {
    addLog("Installation aborted");
    addLog("Please view /tmp/install.log for details");
    if (Data.root != null) Data.umount(Data.root.device.dev + Data.root.number);
    if (Linux.distro == Linux.DistroTypes.Fedora) {
      if (fedoraMount) {
        Data.umount("/mnt/src");
        fedoraMount = false;
      }
    }
    Installer.enableFinish();
  }

  public void shellProcessOutput(String str) {
    int newFilesCopied = str.split("\n").length - 1;
    if (calcFilesToCopy) {
      filesToCopy += newFilesCopied;
    } else {
      totalFilesCopied += newFilesCopied;
      progress.setValue(totalFilesCopied * 100 / filesToCopy);
    }
  }

  public IPanel next() {return null;}
  public IPanel prev() {return null;}
  public IPanel getThis() {return this;}
}
